iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0
自我挑戰組

30天深入淺出Redux系列 第 13

Redux 深入淺出 - [ Day 13 ] Redux Toolkit Slice

  • 分享至 

  • xImage
  •  

前一篇我們有介紹了 Redux toolkit 並且示範他是如何簡化及整併原本的專案的,那麼今天我們就陸續將其他兩項商品也搬移進現在的專案裡面吧!

在成功的移植了咖啡這項商品之後,接著我們來處理咖啡豆吧!

還記得嗎?先從 slice 開始,讓我們去對應原本的 coffeeBeanReducer 裏面的 initialState,並於目前專案下的 features/slices 內新增 coffeeBeanSlice.js 的檔案,對照之前的 reducer 並作以下的處理:

// features/slices/coffeeBeanSlice.js
const { createSlice } = require("@reduxjs/toolkit");

// only 的 coffeeBean
const initialState = {
  numOfCoffeeBean: 20
}

const coffeeBeanSlice = createSlice({
  name: 'coffeeBean',
  initialState,
  reducers: {
    coffeeBeanOrdered: (state, action) => {
      state.numOfCoffeeBean = state.numOfCoffeeBean - action.payload
      return state;
    },
    coffeeBeanRestocked: (state, action) => {
      state.numOfCoffeeBean = state.numOfCoffeeBean + action.payload
      return state;
    },
  }
})

module.exports = coffeeBeanSlice.reducer;
module.exports.coffeeBeanActions = coffeeBeanSlice.actions;

因為 slice 整合了 action & reducer 的部分,所以在這裡可以很直觀地完成一條龍的作業,從原本 Reducer 檔案裡面的 initialstate 到 action 的對應,這裡可以發現 redux toolkit 幫我們把 action 作為參數帶到 reducer 裡面,這樣一來就不需要去額外定義 types 的檔案了。

https://ithelp.ithome.com.tw/upload/images/20220922/20129020JdXeRNSeKA.png

和前一篇處理咖啡基本是一樣的,所以按流程我們現在必須回到 store.js 內去定義剛才新增的 slice :

// features/store.js
const configureStore = require('@reduxjs/toolkit').configureStore;
const coffeeReducer = require('./slices/coffeeSlice');
const coffeeBeanReducer = require('./slices/coffeeBeanSlice');

const store = configureStore({
  reducer: {
    coffee: coffeeReducer,
    coffeeBean: coffeeBeanReducer,
  }
})

module.exports = { store }

一樣我們於 index.js 內做以下呼叫,並測試看看:

// ./index.js
const { store } = require('./features/store');
const coffeeActions = require('./features/slices/coffeeSlice').coffeeActions;
const coffeeBeanActions = require('./features/slices/coffeeBeanSlice').coffeeBeanActions;

console.log('Initial State', store.getState());
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()));

store.dispatch(coffeeActions.coffeeOrdered(1));
store.dispatch(coffeeActions.coffeeOrdered(4));
store.dispatch(coffeeActions.coffeeRestocked(10));
store.dispatch(coffeeBeanActions.coffeeBeanOrdered(2));
store.dispatch(coffeeBeanActions.coffeeBeanRestocked(5));

unsubscribe();

那麼,終端機會出現以下訊息:

Initial State { coffee: { numOfCoffee: 20 }, coffeeBean: { numOfCoffeeBean: 20 } }
更新 { coffee: { numOfCoffee: 19 }, coffeeBean: { numOfCoffeeBean: 20 } }
更新 { coffee: { numOfCoffee: 15 }, coffeeBean: { numOfCoffeeBean: 20 } }
更新 { coffee: { numOfCoffee: 25 }, coffeeBean: { numOfCoffeeBean: 20 } }
更新 { coffee: { numOfCoffee: 25 }, coffeeBean: { numOfCoffeeBean: 18 } }
更新 { coffee: { numOfCoffee: 25 }, coffeeBean: { numOfCoffeeBean: 23 } }

差不多的概念,我們還有一項蛋糕的商品,也做一樣的處理,先新增一個 cakeSlice.js,如下:

// features/slices/cakeSlice.js
const { createSlice } = require("@reduxjs/toolkit");

// 比照 only 的 cakeReducer
const initialState = {
  numOfCake: 20
}

const cakeSlice = createSlice({
  name: 'cake',
  initialState,
  reducers: {
    cakeOrdered: (state, action) => {
      state.numOfCake = state.numOfCake - action.payload
      return state;
    },
    cakeRestocked: (state, action) => {
      state.numOfCake = state.numOfCake + action.payload
      return state;
    },
  }
})

module.exports = cakeSlice.reducer;
module.exports.cakeActions = cakeSlice.actions;

這裡大家就當練習熟悉一下 redux-toolkit 整合的做法,完成後,一樣回到 store.js 去做調整:

// features/store.js
const configureStore = require('@reduxjs/toolkit').configureStore;
const coffeeReducer = require('./slices/coffeeSlice');
const coffeeBeanReducer = require('./slices/coffeeBeanSlice');
const cakeReducer = require('./slices/cakeSlice');

const store = configureStore({
  reducer: {
    coffee: coffeeReducer,
    coffeeBean: coffeeBeanReducer,
    cake: cakeReducer,
  }
})

module.exports = { store }

最後,於 index.js 內我們測試呼叫看看以下:

// ./index.js
const { store } = require('./features/store');
const coffeeActions = require('./features/slices/coffeeSlice').coffeeActions;
const coffeeBeanActions = require('./features/slices/coffeeBeanSlice').coffeeBeanActions;
const cakeActions = require('./features/slices/cakeSlice').cakeActions;

console.log('Initial State', store.getState());
const unsubscribe = store.subscribe(() => console.log('更新', store.getState()));

store.dispatch(coffeeActions.coffeeOrdered(1));
store.dispatch(coffeeActions.coffeeOrdered(4));
store.dispatch(coffeeActions.coffeeRestocked(10));
store.dispatch(coffeeBeanActions.coffeeBeanOrdered(2));
store.dispatch(coffeeBeanActions.coffeeBeanRestocked(5));
store.dispatch(cakeActions.cakeOrdered(3));
store.dispatch(cakeActions.cakeRestocked(6));

unsubscribe();

成功的話會如以下看到 cake 有減少和增加:

Initial State {
  coffee: { numOfCoffee: 20 },
  coffeeBean: { numOfCoffeeBean: 20 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 19 },
  coffeeBean: { numOfCoffeeBean: 20 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 15 },
  coffeeBean: { numOfCoffeeBean: 20 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 25 },
  coffeeBean: { numOfCoffeeBean: 20 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 25 },
  coffeeBean: { numOfCoffeeBean: 18 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 25 },
  coffeeBean: { numOfCoffeeBean: 23 },
  cake: { numOfCake: 20 }
}
更新 {
  coffee: { numOfCoffee: 25 },
  coffeeBean: { numOfCoffeeBean: 23 },
  cake: { numOfCake: 17 }
}
更新 {
  coffee: { numOfCoffee: 25 },
  coffeeBean: { numOfCoffeeBean: 23 },
  cake: { numOfCake: 23 }
}

這樣大家應該比較熟悉基本的運作了吧!

可是像 slice 這樣的做法不就沒有辦法同時作用於兩個不同的 Reducer 了嗎?

是的,這也是為什麼我們還沒處理資金的原因,下一篇我們來介紹 Redux toolkit 是如何同時影響兩個 state 的了。


上一篇
Redux 深入淺出 - [ Day 12 ] Redux Toolkit 簡介
下一篇
Redux 深入淺出 - [ Day 14 ] Redux Toolkit ExtraReducer
系列文
30天深入淺出Redux31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言